package com.catjiu.wangEditor.common;

import cn.hutool.core.bean.BeanUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.catjiu.wangEditor.entity.*;
import org.apache.poi.xwpf.usermodel.*;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.*;

import java.math.BigInteger;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class DomConvert {
    /**
     * 前端传回来的结构转成dom节点
     * @param array
     * @return
     */
    public static List<DomNode> toDomNodeList(JSONArray array){
        List<DomNode> doms = new ArrayList<>();
        for (Object o : array) {
            JSONObject obj = (JSONObject) JSONObject.toJSON(o);
            if (obj.containsKey("type")){
                DomNode domNode = toDomNode(obj);
                doms.add(domNode);
                if(obj.containsKey("children")){
                    domNode.setChildren(toDomNodeList(obj.getJSONArray("children")));
                }
            }else{
                DomText domText = DomText.from(obj);
                doms.add(domText);
            }
        }
        return doms;
    }

    /**
     * 有类型的节点转换
     * @param object
     * @return
     */
    private static DomNode toDomNode(JSONObject object){
        JSONObject copy = new JSONObject();
        BeanUtil.copyProperties(object,copy);
        copy.remove("children");
        object = copy;
        switch (object.getString("type")){
            case "paragraph":
                return object.toJavaObject(DomParagraph.class);
            case "image":
                return object.toJavaObject(DomImage.class);
            case "link":
                return object.toJavaObject(DomLink.class);
            case "bulleted-list":
                return object.toJavaObject(DomBulletedList.class);
            case "numbered-list":
                return object.toJavaObject(DomNumberedList.class);
            case "list-item":
                return object.toJavaObject(DomListItem.class);
            case "table":
                return object.toJavaObject(DomTable.class);
            case "table-row":
                return object.toJavaObject(DomTableRow.class);
            case "table-cell":
                return object.toJavaObject(DomTableCell.class);
            case "divider":
                return object.toJavaObject(DomDivider.class);
        }
        //header
        String header;
        if((header = object.getString("type")).startsWith("header")){
            DomHeader domHeader = object.toJavaObject(DomHeader.class);
            int level =Integer.parseInt(header.replace("header",""));
            domHeader.setLevel(level);
            return domHeader;
        }
        return null;
    }

    /**
     * Dom节点转word
     * @param list
     */
    public static XWPFDocument toWord(List<DomNode> list) {
        XWPFDocument doc = new XWPFDocument();
        //初始化标题类型
        initStyles(doc);
        //初始化列表
        initNumbering(doc);
        for (DomNode domNode : list) {
            switch (domNode.getType()){
                case "paragraph":
                    appendParagraph(doc, (DomParagraph) domNode);
                    break;
                case "header":
                    appendHeader(doc,(DomHeader)domNode);
                    break;
                case "bulleted-list":
                    appendBulletedList(doc,(DomBulletedList)domNode);
                    break;
                case "numbered-list":
                    appendNumberedList(doc,(DomNumberedList)domNode);
                    break;
                case "table":
                    appendTable(doc,(DomTable)domNode);
                    break;
                case "divider":
                    appendDivider(doc,(DomDivider)domNode);
                    break;
                default:
                    throw new RuntimeException("未知type");
            }
        }
        return doc;
    }

    /**
     * 定义一些styles
     * @param doc
     */
    private static void initStyles(XWPFDocument doc) {
        XWPFStyles styles = doc.getStyles()==null?doc.createStyles():doc.getStyles();
        CTStyle ctStyle = CTStyle.Factory.newInstance();
        CTOnOff ctOnOff = CTOnOff.Factory.newInstance();
        ctStyle.setUnhideWhenUsed(ctOnOff);
        ctStyle.setQFormat(ctOnOff);
        //标题
        addHeaderStyle(ctStyle,styles);
        //无序列表
        addWxlbStyle(ctStyle,styles);
    }
    private static Map<String,BigInteger> numberingIdMap = new HashMap<>();
    /**
     * 定义列表
     * @param doc
     */
    private static void initNumbering(XWPFDocument doc){
        XWPFNumbering numbering = doc.createNumbering();
        //无序列表
        CTAbstractNum abstractNum = CTAbstractNum.Factory.newInstance();
        abstractNum.setAbstractNumId(BigInteger.valueOf(0));
        //列表级别类型
        CTMultiLevelType ctMultiLevelType = abstractNum.addNewMultiLevelType();
        ctMultiLevelType.setVal(STMultiLevelType.MULTILEVEL);
        //定义级别 - 0
        CTLvl ctLvl = abstractNum.addNewLvl();
        ctLvl.setIlvl(BigInteger.ZERO);
        ctLvl.setStart(cTDecimalNumberOf(1));
        ctLvl.addNewNumFmt().setVal(STNumberFormat.BULLET);
        ctLvl.addNewLvlText().setVal("\uF06C");
        ctLvl.addNewLvlJc().setVal(STJc.LEFT);
        CTInd ctInd = ctLvl.addNewPPr().addNewInd();
        ctInd.setLeft(420);
        ctInd.setHanging(420);
        XWPFAbstractNum wxlb = new XWPFAbstractNum(abstractNum,numbering);
        numbering.addAbstractNum(wxlb);
        BigInteger bigInteger = numbering.addNum(abstractNum.getAbstractNumId());
        numberingIdMap.put("无序列表",bigInteger);
//        //有序列表
//        CTAbstractNum abstractNum_1 = CTAbstractNum.Factory.newInstance();
//        abstractNum_1.setAbstractNumId(BigInteger.valueOf(1));
//        //列表级别类型
//        CTMultiLevelType ctMultiLevelType_1 = abstractNum.addNewMultiLevelType();
//        ctMultiLevelType_1.setVal(STMultiLevelType.MULTILEVEL);
//        //定义级别 - 0
//        CTLvl ctLvl_1 = abstractNum.addNewLvl();
//        ctLvl_1.setIlvl(BigInteger.ZERO);
//        ctLvl_1.setStart(cTDecimalNumberOf(1));
//        ctLvl_1.addNewNumFmt().setVal(STNumberFormat.DECIMAL);
//        ctLvl_1.addNewLvlText().setVal("\uF06e");
//        ctLvl_1.addNewLvlJc().setVal(STJc.LEFT);
//        CTTabStop tab = ctLvl.addNewPPr().addNewTabs().addNewTab();
//        tab.setVal(STTabJc.NUM);
//        tab.setPos(720);
//        CTInd ctInd_1 = ctLvl.getPPr().addNewInd();
//        ctInd_1.setLeft(720);
//        ctInd_1.setHanging(720);
//        XWPFAbstractNum yxlb = new XWPFAbstractNum(abstractNum_1,numbering);
//        numbering.addAbstractNum(yxlb);
//        BigInteger bigInteger1 = numbering.addNum(abstractNum_1.getAbstractNumId());
//        numberingIdMap.put("有序列表",bigInteger1);
    }

    /**
     * 添加标题style
     * @param ctStyle
     * @param styles
     */
    private static void addHeaderStyle(CTStyle ctStyle, XWPFStyles styles){
        for (int i=1;i<=10;i++){
            XWPFStyle style = new XWPFStyle(ctStyle,styles);
            style.setStyleId("标题"+i);
            CTString ctString = CTString.Factory.newInstance();
            ctString.setVal("标题"+i);
            ctStyle.setBasedOn(ctString);
            CTDecimalNumber decimalNumber = CTDecimalNumber.Factory.newInstance();
            decimalNumber.setVal(BigInteger.valueOf(i-1));
            ctStyle.setUiPriority(decimalNumber);
            CTPPrGeneral ppr = CTPPrGeneral.Factory.newInstance();
            ppr.setOutlineLvl(decimalNumber);
            CTSpacing spacing = ppr.isSetSpacing() ? ppr.getSpacing() : ppr.addNewSpacing();
            spacing.setLineRule(STLineSpacingRule.AUTO);
            spacing.setBefore(BigInteger.valueOf(240));
            spacing.setAfter(BigInteger.valueOf(240));
            spacing.setLine(BigInteger.valueOf((long) (240*(i==1?1.5:1.33))));
            ctStyle.setPPr(ppr);
            style.setType(STStyleType.PARAGRAPH);
            styles.addStyle(style);
        }
    }

    /**
     * 添加无序列表style
     * @param ctStyle
     * @param styles
     */
    private static void addWxlbStyle(CTStyle ctStyle, XWPFStyles styles){
        XWPFStyle wxlb = new XWPFStyle(ctStyle,styles);
        wxlb.setStyleId("无序列表");
        CTString ctString = CTString.Factory.newInstance();
        ctString.setVal("无序列表");
        ctStyle.setBasedOn(ctString);
        CTPPrGeneral ppr=ctStyle.getPPr();
        if(ppr == null){
            ppr =CTPPrGeneral.Factory.newInstance();
            ctStyle.setPPr(ppr);
        }
        CTNumPr numPr = ppr.getNumPr();
        if(numPr==null){
            numPr = CTNumPr.Factory.newInstance();
            ppr.setNumPr(numPr);
        }
        numPr.setIlvl(cTDecimalNumberOf(0));
        numPr.setNumId(cTDecimalNumberOf(1));
        wxlb.setType(STStyleType.PARAGRAPH);
        styles.addStyle(wxlb);
    }

    private static CTDecimalNumber cTDecimalNumberOf(int v){
        CTDecimalNumber olvl = CTDecimalNumber.Factory.newInstance();
        olvl.setVal(BigInteger.valueOf(v));
        return  olvl;
    }
    private static CTString ctStringOf(String str){
        CTString ctString = CTString.Factory.newInstance();
        ctString.setVal(str);
        return ctString;
    }
    private static void appendDivider(XWPFDocument doc, DomDivider domNode) {
    }

    private static void appendTable(XWPFDocument doc, DomTable domNode) {
    }

    private static void appendNumberedList(XWPFDocument doc, DomNumberedList domNode) {
    }

    private static void appendBulletedList(XWPFDocument doc, DomBulletedList domNode) {
        for (DomNode child : domNode.getChildren()) {
            XWPFParagraph paragraph = appendParagraph(doc, (DomListItem)child);
            paragraph.setStyle("无序列表");
            CTPPr ppr = paragraph.getCTP().addNewPPr();
            ppr.addNewPStyle().setVal("ad");
            CTNumPr numPr = ppr.addNewNumPr();
            numPr.setIlvl(cTDecimalNumberOf(0));
            numPr.setNumId(cTDecimalNumberOf(0));
        }
    }

    private static void appendHeader(XWPFDocument doc, DomHeader domNode) {
        for (DomNode child : domNode.getChildren()) {
            if(child instanceof DomText){
                DomText text = (DomText) child;
                if(text.getBold() == null){
                    text.setBold(true);
                }
                if(text.getFontSize() == null){
                    //26 一号  标题从 24开始递减至14
                    int size = Math.max(26 - domNode.getLevel()*2,14);
                    text.setFontSize(size);
                }
            }
        }
        XWPFParagraph paragraph = appendParagraph(doc,domNode);
        paragraph.setStyle("标题"+domNode.getLevel());
    }

    /**
     * 段落写入内容
     * @param paragraph
     * @param domNode
     */
    private static void writeParagraph(XWPFParagraph paragraph, DomParagraph domNode){
        domNode.render(paragraph);
        for (DomNode node : domNode.getChildren()) {
            if (node instanceof DomText) {
                DomText text = (DomText) node;
                XWPFRun run = paragraph.createRun();
                text.render(run);
            } else if (node instanceof DomLink) {
                DomLink link = (DomLink) node;
                XWPFHyperlinkRun hyperlinkRun = paragraph.createHyperlinkRun(link.getUrl());
                //TODO
            }
        }
    }

    /**
     * 添加段落
     * @param doc
     * @param domNode
     * @return
     */
    private static XWPFParagraph appendParagraph(XWPFDocument doc, DomParagraph domNode) {
        XWPFParagraph paragraph = doc.createParagraph();
        writeParagraph(paragraph,domNode);
        return paragraph;
    }
}
